/* LwIP SNTP example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_netif.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "esp_http_client.h"
#include "esp_timer.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"

static const char *TAG = "IP_GET";

// WiFi配置 - 在这里填写你的WiFi账号和密码
#define WIFI_SSID      "Xiaomi_3B61"
#define WIFI_PASSWORD  "MEIYOUMIMA"

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
#define ESP_MAXIMUM_RETRY  5

// HTTP响应缓冲区
static char http_response_buffer[512];
static int http_response_len = 0;

// 添加服务测试结果结构体
typedef struct {
    const char* service_name;
    const char* url;
    bool success;
    int64_t response_time_ms;
    int status_code;
    char response_data[128];
} service_test_result_t;

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "重试连接WiFi");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"连接WiFi失败");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "获得IP地址:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = WIFI_SSID,
            .password = WIFI_PASSWORD,
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        },
    };

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "成功连接到WiFi SSID:%s", WIFI_SSID);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "连接WiFi失败 SSID:%s", WIFI_SSID);
    } else {
        ESP_LOGE(TAG, "意外事件");
    }
}

void get_local_ip(void)
{
    esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
    esp_netif_ip_info_t ip_info;
    
    if (esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) {
        ESP_LOGI(TAG, "==== 内网IP信息 ====");
        ESP_LOGI(TAG, "IP地址: " IPSTR, IP2STR(&ip_info.ip));
        ESP_LOGI(TAG, "子网掩码: " IPSTR, IP2STR(&ip_info.netmask));
        ESP_LOGI(TAG, "网关: " IPSTR, IP2STR(&ip_info.gw));
        ESP_LOGI(TAG, "===================");
    } else {
        ESP_LOGE(TAG, "获取本地IP失败");
    }
}

esp_err_t http_event_handler(esp_http_client_event_t *evt)
{
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            if (!esp_http_client_is_chunked_response(evt->client)) {
                if (http_response_len + evt->data_len < sizeof(http_response_buffer)) {
                    memcpy(http_response_buffer + http_response_len, evt->data, evt->data_len);
                    http_response_len += evt->data_len;
                    http_response_buffer[http_response_len] = '\0';
                }
            }
            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            break;
        case HTTP_EVENT_REDIRECT:
            ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
            break;
    }
    return ESP_OK;
}

void get_public_ip(void)
{
    // 使用两个主要IP查询服务
    const char* service_names[] = {
        "IPIP.NET",
        "HTTPBin备选"
    };
    
    const char* ip_apis[] = {
        "https://myip.ipip.net/json",               // IPIP.NET - 主要服务
        "http://httpbin.org/ip"                     // HTTPBin - 备选服务
    };
    
    int service_count = sizeof(ip_apis)/sizeof(ip_apis[0]);
    service_test_result_t results[service_count];
    
    ESP_LOGI(TAG, "==== 开始测试所有IP查询服务响应速度 ====");
    
    for (int i = 0; i < service_count; i++) {
        ESP_LOGI(TAG, "测试服务 %d/%d: %s", i+1, service_count, service_names[i]);
        ESP_LOGI(TAG, "URL: %s", ip_apis[i]);
        
        // 初始化结果
        results[i].service_name = service_names[i];
        results[i].url = ip_apis[i];
        results[i].success = false;
        results[i].response_time_ms = 0;
        results[i].status_code = 0;
        memset(results[i].response_data, 0, sizeof(results[i].response_data));
        
        // 记录开始时间
        int64_t start_time = esp_timer_get_time();
        
        http_response_len = 0;
        memset(http_response_buffer, 0, sizeof(http_response_buffer));
        
        esp_http_client_config_t config = {
            .url = ip_apis[i],
            .event_handler = http_event_handler,
            .timeout_ms = 15000,    // 增加超时时间
        };
        
        // 如果是HTTPS URL，需要配置SSL
        if (strncmp(ip_apis[i], "https://", 8) == 0) {
            config.transport_type = HTTP_TRANSPORT_OVER_SSL;
            config.skip_cert_common_name_check = false;  // 启用证书域名检查
            config.use_global_ca_store = false;          // 不使用全局CA证书
            config.crt_bundle_attach = esp_crt_bundle_attach;  // 使用ESP32内置证书包
        } else {
            config.transport_type = HTTP_TRANSPORT_OVER_TCP;  // HTTP使用TCP传输
        }
        
        esp_http_client_handle_t client = esp_http_client_init(&config);
        esp_err_t err = esp_http_client_perform(client);
        
        // 记录结束时间并计算响应时间
        int64_t end_time = esp_timer_get_time();
        results[i].response_time_ms = (end_time - start_time) / 1000; // 转换为毫秒
        
        if (err == ESP_OK) {
            int status_code = esp_http_client_get_status_code(client);
            results[i].status_code = status_code;
            
            if (status_code == 200) {
                results[i].success = true;
                // 保存响应数据（截取前127个字符）
                if (http_response_len > 0) {
                    int copy_len = (http_response_len < 127) ? http_response_len : 127;
                    memcpy(results[i].response_data, http_response_buffer, copy_len);
                    results[i].response_data[copy_len] = '\0';
                }
                
                ESP_LOGI(TAG, "✓ 成功 - 响应时间: %lld毫秒, 状态码: %d", 
                         results[i].response_time_ms, status_code);
                ESP_LOGI(TAG, "  响应内容: %s", results[i].response_data);
            } else {
                ESP_LOGW(TAG, "✗ HTTP状态码错误: %d, 响应时间: %lld毫秒", 
                         status_code, results[i].response_time_ms);
            }
        } else {
            ESP_LOGE(TAG, "✗ 请求失败: %s, 耗时: %lld毫秒", 
                     esp_err_to_name(err), results[i].response_time_ms);
        }
        
        esp_http_client_cleanup(client);
        
        // 服务间等待
        if (i < service_count - 1) {
            ESP_LOGI(TAG, "等待2秒后测试下一个服务...");
            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }
    }
    
    // 显示测试总结
    ESP_LOGI(TAG, "");
    ESP_LOGI(TAG, "==== 服务响应速度测试总结 ====");
    ESP_LOGI(TAG, "格式: [排名] 服务名 - 响应时间 - 状态");
    ESP_LOGI(TAG, "");
    
    // 找出成功的服务并按响应时间排序
    service_test_result_t* successful_services[service_count];
    int success_count = 0;
    
    // 收集成功的服务
    for (int i = 0; i < service_count; i++) {
        if (results[i].success) {
            successful_services[success_count] = &results[i];
            success_count++;
        }
    }
    
    // 按响应时间排序（冒泡排序）
    for (int i = 0; i < success_count - 1; i++) {
        for (int j = 0; j < success_count - 1 - i; j++) {
            if (successful_services[j]->response_time_ms > successful_services[j + 1]->response_time_ms) {
                service_test_result_t* temp = successful_services[j];
                successful_services[j] = successful_services[j + 1];
                successful_services[j + 1] = temp;
            }
        }
    }
    
    // 显示成功的服务（按速度排序）
    if (success_count > 0) {
        ESP_LOGI(TAG, "成功的服务（按响应速度排序）:");
        for (int i = 0; i < success_count; i++) {
            ESP_LOGI(TAG, "[%d] %s - %lld毫秒 - ✓成功", 
                     i+1, 
                     successful_services[i]->service_name,
                     successful_services[i]->response_time_ms);
        }
        
        ESP_LOGI(TAG, "");
        ESP_LOGI(TAG, "⭐ 推荐使用最快的服务: %s (响应时间: %lld毫秒)", 
                 successful_services[0]->service_name,
                 successful_services[0]->response_time_ms);
        ESP_LOGI(TAG, "   URL: %s", successful_services[0]->url);
    }
    
    // 显示失败的服务
    ESP_LOGI(TAG, "");
    ESP_LOGI(TAG, "失败的服务:");
    bool has_failures = false;
    for (int i = 0; i < service_count; i++) {
        if (!results[i].success) {
            has_failures = true;
            ESP_LOGI(TAG, "✗ %s - %lld毫秒 - 状态码:%d", 
                     results[i].service_name,
                     results[i].response_time_ms,
                     results[i].status_code);
        }
    }
    if (!has_failures) {
        ESP_LOGI(TAG, "无失败服务 - 所有服务都响应正常！");
    }
    
    ESP_LOGI(TAG, "");
    ESP_LOGI(TAG, "==== 测试完成 ====");
}

void app_main(void)
{
    ESP_LOGI(TAG, "==== ESP32 IP获取程序启动 ====");
    ESP_LOGI(TAG, "配置的WiFi SSID: %s", WIFI_SSID);
    
    // 初始化NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();

    // 获取内网IP
    get_local_ip();

    // 获取公网IP
    get_public_ip();

    ESP_LOGI(TAG, "==== IP获取完成 ====");
    
    // 程序完成后保持运行
    while(1) {
        vTaskDelay(30000 / portTICK_PERIOD_MS); // 每30秒重新获取一次
        ESP_LOGI(TAG, "重新获取IP信息...");
        get_local_ip();
        get_public_ip();
    }
}
